package com.aws.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.appengine.api.NamespaceManager;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterPredicate;
import com.google.gson.Gson;

@SuppressWarnings("serial")
public class ServerEvents extends HttpServlet {
	DatastoreService dataStore = DatastoreServiceFactory.getDatastoreService();

	@SuppressWarnings("static-access")
	public void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		try {
			process(req, res);
		} catch (EntityNotFoundException e) {
			res.setStatus(res.SC_BAD_REQUEST);
			e.printStackTrace();
		}
	}

	@SuppressWarnings("static-access")
	public void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		try {
			process(req, res);
		} catch (EntityNotFoundException e) {
			res.setStatus(res.SC_BAD_REQUEST);
			e.printStackTrace();
		}
	}

	@SuppressWarnings("static-access")
	public void process(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException, EntityNotFoundException {
		String method = req.getMethod();
		String path = req.getPathInfo();

		System.out.println("[" + method + "] : " + req.getRequestURI());

		if (path != null) {
			String[] pathComponents = path.split("/");
			String resource = pathComponents[1];

			System.out.println("Accion sobre un recurso");

			System.out.println(method + "-" + resource);

			if (method.contains("GET")) {
				getSingleEvent(req, res, resource);
			} else {
				res.setStatus(res.SC_METHOD_NOT_ALLOWED);
			}
		} else {
			System.out.println("Accion sobre una lista de recursos");

			if (method.contains("GET")) {
				getEvents(req, res);
			} else if (method.contains("POST")) {
				postEvent(req, res);
			} else {
				res.setStatus(res.SC_METHOD_NOT_ALLOWED);
			}
		}
	}

	@SuppressWarnings("static-access")
	private void getSingleEvent(HttpServletRequest req,
			HttpServletResponse res, String resource)
			throws EntityNotFoundException, IOException {
		Query q = new Query("Token").setFilter(new FilterPredicate("token",
				Query.FilterOperator.EQUAL, req.getParameter("token")));
		PreparedQuery pq = dataStore.prepare(q);
		Iterator<Entity> it = pq.asIterator();

		Entity token = null;

		if (it.hasNext()) {
			token = it.next();
		} else {
			res.setStatus(res.SC_BAD_REQUEST);
		}

		if (token == null) {
			System.out.println("Token invalido");
			res.setStatus(res.SC_BAD_REQUEST);
		} else {
			System.out.println("Token valido");

			Entity user = getUserByUsername((String) token
					.getProperty("usuario"));
			String grupo = (String) user.getProperty("grupo");
			grupo = grupo.replaceAll("\\s+", "_");

			if (NamespaceManager.get() == null) {
				NamespaceManager.set(grupo);
			}
			System.out.println(NamespaceManager.get());

			Key key = KeyFactory.createKey(Event.class.getSimpleName(),
					Integer.parseInt(resource));
			Entity e = DatastoreServiceFactory.getDatastoreService().get(key);

			if (e != null) {
				Event event = new Event((String) e.getProperty("titulo"),
						(String) e.getProperty("descripcion"),
						(String) e.getProperty("ciudad"),
						(String) e.getProperty("longitud"),
						(String) e.getProperty("latitud"),
						(String) e.getProperty("fechaInicio"),
						(String) e.getProperty("fechaFin"),
						(String) e.getProperty("horaInicio"),
						(String) e.getProperty("horaFin"),
						(String) e.getProperty("creadoPor"),
						(String) e.getProperty("hashtag"));
				Gson gson = new Gson();
				String jsonStringRes = gson.toJson(event);

				res.setContentType("application/json");
				res.getWriter().println(jsonStringRes);
			} else {
				res.setStatus(res.SC_BAD_REQUEST);
			}
		}
		NamespaceManager.set(null);
	}

	@SuppressWarnings("static-access")
	private void getEvents(HttpServletRequest req, HttpServletResponse res)
			throws IOException {
		Query q = new Query("Token").setFilter(new FilterPredicate("token",
				Query.FilterOperator.EQUAL, req.getParameter("token")));
		PreparedQuery pq = dataStore.prepare(q);
		Iterator<Entity> it = pq.asIterator();

		Entity token = null;

		if (it.hasNext()) {
			token = it.next();
		} else {
			res.setStatus(res.SC_BAD_REQUEST);
		}

		if (token == null) {
			System.out.println("Token invalido");
			res.setStatus(res.SC_BAD_REQUEST);
		} else {
			System.out.println("Token valido");

			Entity user = getUserByUsername((String) token
					.getProperty("usuario"));
			String grupo = (String) user.getProperty("grupo");
			grupo = grupo.replaceAll("\\s+", "_");

			if (NamespaceManager.get() == null) {
				NamespaceManager.set(grupo);
			}
			System.out.println(NamespaceManager.get());

			q = new Query("Event");

			pq = dataStore.prepare(q);
			it = pq.asIterator();

			List<Event> events = new ArrayList<Event>();

			while (it.hasNext()) {
				Entity e = it.next();
				/*
				 * Event event = new Event((String) e.getProperty("titulo"),
				 * (String) e.getProperty("descripcion"), (String)
				 * e.getProperty("ciudad"), (String) e.getProperty("longitud"),
				 * (String) e.getProperty("latitud"), (String)
				 * e.getProperty("fechaInicio"), (String)
				 * e.getProperty("fechaFin"), (String)
				 * e.getProperty("horaInicio"), (String)
				 * e.getProperty("horaFin"), (String)
				 * e.getProperty("creadoPor"), (String)
				 * e.getProperty("hashtag"));
				 */
				Event event = new Event((String) e.getProperty("titulo"),
						(String) e.getProperty("ciudad"),
						(String) e.getProperty("fechaInicio"),
						(String) e.getProperty("horaInicio"),
						(String) e.getProperty("creadoPor"), String.valueOf(e
								.getKey().getId()));
				events.add(event);
			}

			Gson gson = new Gson();
			String jsonStringRes = gson.toJson(events);

			res.setContentType("application/json");
			res.getWriter().println(jsonStringRes);
		}
		NamespaceManager.set(null);
	}

	@SuppressWarnings("static-access")
	public void postEvent(HttpServletRequest req, HttpServletResponse res)
			throws IOException {
		StringBuilder sb = new StringBuilder();
		BufferedReader br = req.getReader();

		String jsonString;
		while ((jsonString = br.readLine()) != null) {
			sb.append(jsonString);
		}
		jsonString = sb.toString();

		Entity token = checkToken(jsonString);

		if (token == null) {
			System.out.println("Token invalido");
			res.setStatus(res.SC_BAD_REQUEST);
		} else {
			System.out.println("Token valido");

			Entity user = getUserByUsername((String) token
					.getProperty("usuario"));
			String grupo = (String) user.getProperty("grupo");
			grupo = grupo.replaceAll("\\s+", "_");

			if (NamespaceManager.get() == null) {
				NamespaceManager.set(grupo);
			}
			System.out.println(NamespaceManager.get());

			Event event = extractEvent(jsonString);

			if (event == null) {
				res.setStatus(res.SC_BAD_REQUEST);
			} else {
				Entity entity = new Entity("Event");
				entity.setProperty("titulo", event.getTitulo());
				entity.setProperty("descripcion", event.getDescripcion());
				entity.setProperty("ciudad", event.getCiudad());
				entity.setProperty("longitud", event.getLongitud());
				entity.setProperty("latitud", event.getLatitud());
				entity.setProperty("fechaInicio", event.getFechaInicio());
				entity.setProperty("fechaFin", event.getFechaFin());
				entity.setProperty("horaInicio", event.getHoraInicio());
				entity.setProperty("horaFin", event.getHoraFin());
				entity.setProperty("creadoPor", event.getCreadoPor());
				entity.setProperty("hashtag", event.getHashtag());

				dataStore.put(entity);
			}
		}
		NamespaceManager.set(null);
	}

	private Event extractEvent(String jsonString) throws IOException {
		Event e = null;

		Gson gson = new Gson();

		try {
			System.out.println("String to be parsed: " + jsonString);
			e = gson.fromJson(jsonString, Event.class);
			System.out.println("Event parsed");
		} catch (Exception exc) {
			System.out.println("ERROR parsing Event: " + exc.getMessage());
		}

		return e;
	}

	private Entity checkToken(String jsonString) throws IOException {
		Token t = null;

		Gson gson = new Gson();

		try {
			System.out.println("String to be parsed: " + jsonString);
			t = gson.fromJson(jsonString, Token.class);
			System.out.println("Event parsed");
		} catch (Exception exc) {
			System.out.println("ERROR parsing Event: " + exc.getMessage());
		}

		Query q = new Query("Token").setFilter(new FilterPredicate("token",
				Query.FilterOperator.EQUAL, t.getToken()));
		PreparedQuery pq = dataStore.prepare(q);
		Iterator<Entity> it = pq.asIterator();

		Entity e = null;

		if (it.hasNext()) {
			e = it.next();
		}

		return e;
	}

	private Entity getUserByUsername(String username) {
		Query q = new Query("User").setFilter(new FilterPredicate("username",
				Query.FilterOperator.EQUAL, username));
		PreparedQuery pq = dataStore.prepare(q);
		Iterator<Entity> it = pq.asIterator();

		Entity e = null;

		if (it.hasNext()) {
			e = it.next();
		}

		return e;
	}
}
